/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  							 static_vector.h

	$Header: /heroes4/static_vector.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( STATIC_VECTOR_H_INCLUDED )
#define STATIC_VECTOR_H_INCLUDED

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include <cstddef>
#include <iterator>
#include <algorithm>
#include <new>

/////////////////////////////////////////////////////////////////////////////
// t_static_vector class template - A statically sized vector based on the
// standary library containers.  This class template can be used in place
// of built-in arrays when you need arrays that have normal C++ object
// behavior instead of the odd behavior of built-in arrays.  Also, you can
// use a t_static_vector<> as a base class.

template < typename t_elem, size_t k_size >
class t_static_vector
{
public:
	// Types
	typedef t_elem				value_type;
	typedef size_t				size_type;
	typedef ptrdiff_t			difference_type;
	typedef value_type &		reference;
	typedef value_type const &	const_reference;
	typedef value_type *		iterator;
	typedef value_type const *	const_iterator;
	typedef std::reverse_iterator< iterator > reverse_iterator;
	typedef std::reverse_iterator< const_iterator > const_reverse_iterator;

	// Static data
	enum { num_elements = k_size };

	// Static member functions
	static size_type size() throw() { return k_size; }

	// Constructors
	t_static_vector();
	explicit t_static_vector( value_type const & val );
	explicit t_static_vector( const_iterator other_iter );
	t_static_vector( t_static_vector const & right );

	~t_static_vector();

	// Manipulators
	iterator begin() throw() { return &m_first; }
	iterator end() throw() { return &m_first + k_size; }
	reverse_iterator rbegin() throw() { return reverse_iterator( end() ); }
	reverse_iterator rend() throw() { return reverse_iterator( begin() ); }
	reference at( size_type pos ) { if ( pos >= k_size ) out_of_range(); return begin()[ pos ]; }
	reference operator[]( size_type pos ) throw() { return begin()[ pos ]; }
	reference front() throw() { return begin()[ 0 ]; }
	reference back() throw() { return begin()[ k_size - 1 ]; }

	t_static_vector const & operator=( t_static_vector const & right );

	// Accessors
	const_iterator begin() const throw() { return &m_first; }
	const_iterator end() const throw() { return &m_first + k_size; }
	const_reverse_iterator rbegin() const throw() { return reverse_iterator( end() ); }
	const_reverse_iterator rend() const throw() { return reverse_iterator( begin() ); }
	const_reference at( size_type pos ) const { if ( pos >= k_size ) out_of_range(); return begin()[ pos ]; }
	const_reference operator[]( size_type pos ) const throw() { return begin()[ pos ]; }
	const_reference front() const throw() { return begin()[ 0 ]; }
	const_reference back() const throw() { return begin()[ k_size - 1 ]; }

	template < typename t_elem2 >
	operator t_static_vector< t_elem2, k_size >() const
	{
		t_static_vector< t_elem2, k_size > result;
		std::copy( begin(), end(), result.begin() );
		return result;
	}

	template < typename t_elem2 >
	bool operator==( t_static_vector< t_elem2, k_size > const & right ) const
	{
		return std::equal( begin(), end(), right.begin() );
	}

	template < typename t_elem2 >
	bool operator!=( t_static_vector< t_elem2, k_size > const & right ) const
	{
		return !( *this == right );
	}

	template < typename t_elem2, size_t k_size2 >
	bool operator<( t_static_vector< t_elem2, k_size2 > const & right ) const
	{
		return std::lexicographical_compare( begin(), end(), right.begin(), right.end() );
	}

	template < typename t_elem2, size_t k_size2 >
	bool operator>( t_static_vector< t_elem2, k_size2 > const & right ) const
	{
		return right < *this;
	}

	template < typename t_elem2, size_t k_size2 >
	bool operator<=( t_static_vector< t_elem2, k_size2 > const & right ) const
	{
		return !( *this > right );
	}

	template < typename t_elem2, size_t k_size2 >
	bool operator>=( t_static_vector< t_elem2, k_size2 > const & right ) const
	{
		return !( *this < right );
	}

private:
	// Data members
	value_type		m_first;
	unsigned char	m_placeholder[ ( k_size > 1 ) ? ( k_size - 1 ) * sizeof( value_type ) : 1 ];

	void out_of_range() const { throw std::out_of_range( "Invalid t_static_vector subscript." ); }
};

/////////////////////////////////////////////////////////////////////////////
template < typename t_elem, size_t k_size >
inline t_static_vector< t_elem, k_size >::t_static_vector()
{
	iterator iter = begin() + 1;

	try
	{
		for ( ; iter != end(); ++iter )
			new ( &*iter ) t_elem();
	}
	catch ( ... )
	{
		while ( iter != begin() + 1 )
		{
			--iter;
			iter->~t_elem();
		}
		throw;
	}
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_elem, size_t k_size >
inline t_static_vector< t_elem, k_size >::t_static_vector( value_type const & val ) : m_first( val )
{
	iterator iter = begin() + 1;

	try
	{
		for ( ; iter != end(); ++iter )
			new ( &*iter ) t_elem( val );
	}
	catch ( ... )
	{
		while ( iter != begin() + 1 )
		{
			--iter;
			iter->~t_elem();
		}
		throw;
	}
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_elem, size_t k_size >
inline t_static_vector< t_elem, k_size >::t_static_vector( const_iterator other_iter ) : m_first( *other_iter++ )
{
	iterator iter = begin() + 1;

	try
	{
		for ( ; iter != end(); ++iter )
			new ( &*iter ) t_elem( *other_iter++ );
	}
	catch ( ... )
	{
		while ( iter != begin() + 1 )
		{
			--iter;
			iter->~t_elem();
		}
		throw;
	}
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_elem, size_t k_size >
inline t_static_vector< t_elem, k_size >::t_static_vector( t_static_vector const & right ) : m_first( right.m_first )
{
	const_iterator right_iter = right.begin() + 1;
	iterator iter = begin() + 1;

	try
	{
		for ( ; iter != end(); ++iter )
			new ( &*iter ) t_elem( *right_iter++ );
	}
	catch ( ... )
	{
		while ( iter != begin() + 1 )
		{
			--iter;
			iter->~t_elem();
		}
		throw;
	}
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_elem, size_t k_size >
inline t_static_vector< t_elem, k_size >::~t_static_vector()
{
	iterator iter = end();
	while ( iter != begin() + 1 )
	{
		--iter;
		iter->~t_elem();
	}
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_elem, size_t k_size >
inline t_static_vector< t_elem, k_size > const & t_static_vector< t_elem, k_size >::operator=( t_static_vector const & right )
{
	if ( this != &right )
		std::copy( right.begin(), right.end(), begin() );

	return *this;
}

#endif // !defined( STATIC_VECTOR_H_INCLUDED )
